using System;
using System.Collections.Generic;
using System.Linq;
using Godot;

public enum DIR
{
    DOWN,
    LEFT,
    RIGHT,
    UP
}

public enum ANI_TYPE
{
    IDLE,
    WALK,
    ATTACK,
}

public enum SKILL_ID
{
    SKILL_PYHSICS,
    SKILL_REMOTE,
}
public enum SKILL_TARGET
{
    //可以就地施放
    NO_TARGET,
    //需要一个敌人
    ENEMY_TARGET,
}
public enum CHA_TYPE
{
    FRIEND,
    ENEMY,
}

public enum SKILL_RE
{
    SUCCESS,
    UNKNOW,
    NO_TARGET,

    NO_ENOUGH_DIS,
}
public class CHelp
{
    public static void free(Node n, bool removeFromParentFirst = true)
    {
        if (n == null)
            return;
        if (removeFromParentFirst)
            n.GetParent()?.RemoveChild(n);
        n.QueueFree();
    }
    public static Node insScene(string path)
    {
        // Load the scene at the given path
        if (!ResourceLoader.Exists(path))
            return null;

        var scene = GD.Load<PackedScene>(path);
        if (scene != null)
        {
            Node re = scene.Instantiate();
            return re;
        }
        return null;
    }
    public static bool checkDis(NCharacter cha, NCharacter other, float dis)
    {
        if (cha.GlobalPosition.DistanceTo(other.GlobalPosition) <= dis + cha.ColShapeDis + other.ColShapeDis)
        {
            return true;
        }
        return false;
    }
    public static NCharacter getTeamCha(Node n)
    {
        return getNodeInGroup<NCharacter>(n, CHA_TYPE.FRIEND.ToString());
    }
    public static List<NCharacter> getChas(Node2D n, float radius)
    {
        List<NCharacter> chas = new List<NCharacter>();
        PhysicsShapeQueryParameters2D query = new PhysicsShapeQueryParameters2D();
        query.CollideWithAreas = false;
        query.CollideWithBodies = true;
        //1 2 4 8 -> 1层 2层 3层 4层
        //           01  10 100 1000
        //             11  110
        query.CollisionMask = 1;
        CircleShape2D circleShape2D = new CircleShape2D();
        circleShape2D.Radius = radius;
        query.Shape = circleShape2D;
        query.Transform = new Transform2D(0, n.GlobalPosition);

        var space = n.GetWorld2D().DirectSpaceState;
        foreach (Godot.Collections.Dictionary findObj in space.IntersectShape(query))
        {
            Variant fo = findObj["collider"];
            if (fo.VariantType == Variant.Type.Object)
            {
                if (fo.AsGodotObject() is NCharacter tarCha)
                {
                    chas.Add(tarCha);
                }
            }
        }

        return chas;
    }
    public static NCharacter getNearestEnemy(NCharacter cha, float radius)
    {
        List<NCharacter> chas = getChas(cha, radius);
        List<NCharacter> enemys = new List<NCharacter>();
        foreach (var v in chas)
        {
            if (v == cha)
                continue;

            if (canBattle(v, cha))
            {
                enemys.Add(v);
            }
        }
        List<NCharacter> orderEnemys = enemys.OrderBy(i => i.GlobalPosition.DistanceSquaredTo(cha.GlobalPosition)).ToList();
        if(orderEnemys.Count > 0)
        {
            return orderEnemys[0];
        }

        return null;
    }
    public static NCharacter getChaWithPosition(Node2D n, Vector2 globalPos)
    {
        PhysicsPointQueryParameters2D query = new PhysicsPointQueryParameters2D();
        query.CollideWithAreas = false;
        query.CollideWithBodies = true;
        //1 2 4 8 -> 1层 2层 3层 4层
        //           01  10 100 1000
        //             11  110
        query.CollisionMask = 1;
        query.Position = globalPos;
        var space = n.GetWorld2D().DirectSpaceState;
        foreach (Godot.Collections.Dictionary findObj in space.IntersectPoint(query))
        {
            Variant fo = findObj["collider"];
            if (fo.VariantType == Variant.Type.Object)
            {
                if (fo.AsGodotObject() is NCharacter tarCha)
                {
                    return tarCha;
                }
            }
        }

        return null;
    }
    public static T loadRes<T>(string resPath) where T : Resource
    {
        if (!ResourceLoader.Exists(resPath))
            return null;
        return ResourceLoader.Load<Resource>(resPath) as T;
    }
    public static bool doMove(NCharacter cha, Vector2 tarPos, double delta)
    {
        if (cha.mData.mMoveSpeed * (float)delta > cha.GlobalPosition.DistanceTo(tarPos))
        {
            return true;
        }
        cha.mData.mDir = checkDir(cha.GlobalPosition, tarPos);
        cha.Velocity = (tarPos - cha.GlobalPosition).Normalized() * cha.mData.mMoveSpeed;
        cha.MoveAndSlide();
        return false;
    }
    public static bool canBattle(NCharacter cha, NCharacter other)
    {
        if (cha.mData.mChaType == CHA_TYPE.FRIEND && other.mData.mChaType == CHA_TYPE.ENEMY)
            return true;
        if (other.mData.mChaType == CHA_TYPE.FRIEND && cha.mData.mChaType == CHA_TYPE.ENEMY)
            return true;

        return false;
    }
    public static void setCustomMouse(Resource image)
    {
        if (image == null)
        {
            Input.SetCustomMouseCursor(null);
            return;
        }
        CompressedTexture2D ig = image as CompressedTexture2D;
        Input.SetCustomMouseCursor(image, Input.CursorShape.Arrow, new Vector2(ig.GetWidth() / 2, ig.GetHeight() / 2));
    }
    public static DIR checkDir(Vector2 pos, Vector2 target)
    {
        Vector2 dir = target - pos;
        if (Math.Abs(dir.X) > Math.Abs(dir.Y))
        {
            if (target.X > pos.X)
                return DIR.RIGHT;
            else
                return DIR.LEFT;
        }
        else
        {
            if (target.Y > pos.Y)
                return DIR.DOWN;
            else
                return DIR.UP;
        }
    }

    public static void addToGroup(Node n, string group)
    {
        if (!n.IsInGroup(group))
        {
            n.AddToGroup(group, true);
        }
    }

    public static T getNodeInGroup<T>(Node node, string group) where T : Node
    {
        return node.GetTree().GetFirstNodeInGroup(group) as T;
    }
}